package com.gooluke.shorten.util;

/**
 * @author gooluke
 * description
 * datetime 2025-03-30 1:23
 */
public class DistributedIdGenerator {

    private static final long START_TIMESTAMP = 1704038400000L; // 2024-01-01
    private static final long DATA_CENTER_BITS = 5L;
    private static final long WORKER_BITS = 5L;
    private static final long SEQUENCE_BITS = 12L;

    private final long dataCenterId;
    private final long workerId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    public DistributedIdGenerator() {
        this.dataCenterId = 1; // 实际应从配置读取
        this.workerId = 1;     // 实际应从配置读取 工作节点ID应从配置中心获取，确保集群不重复
    }

    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨异常");
        }

        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & ((1 << SEQUENCE_BITS) - 1);
            if (sequence == 0) {
                timestamp = tilNextMillis();
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - START_TIMESTAMP) << (DATA_CENTER_BITS + WORKER_BITS + SEQUENCE_BITS))
                | (dataCenterId << (WORKER_BITS + SEQUENCE_BITS))
                | (workerId << SEQUENCE_BITS)
                | sequence;
    }

    private long tilNextMillis() {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

}
